package com.fcai.microserv.jwt;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.tuple.Pair;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.Map;

/**
 * jwt令牌管理
 */
@Setter
@Getter
public class FcaiJwtTokenManager {
    private long activeTime;
    private String secretSalt;
    private String httpHeader;
    private Map<String,String[]> userTypeMapper;

    /**
     * 解析jwt令牌
     * @param jwtToken 令牌
     * @return claims
     * @throws io.jsonwebtoken.JwtException
     */
    public Claims parseJwtToken(String jwtToken) {
        return Jwts.parser().setSigningKey(this.generateKey()).parseClaimsJws(jwtToken).getBody();
    }

    /**
     *
     * @param subjectType 主体类型
     * @param subjectId   主体标识
     * @param extendedClaims 附加的属性
     * @return jwtToken
     */
    public String createJwt(String subjectType, String subjectId, Map.Entry<String, String>[] extendedClaims) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMills = System.currentTimeMillis();
        Date now = new Date(nowMills);

        SecretKey key = this.generateKey();
        JwtBuilder builder = Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .signWith(signatureAlgorithm, key)
                .setExpiration(new Date(nowMills + activeTime * 1000))
                .setNotBefore(now);

        if (extendedClaims == null) {
            extendedClaims = new Pair[]{};
        }
        extendedClaims = ArrayUtils.add(extendedClaims, Pair.of(JwtConst.JWT_SUBJECT_TYPE, subjectType));
        extendedClaims = ArrayUtils.add(extendedClaims, Pair.of(JwtConst.JWT_SUBJECT_ID, subjectId));
        for (Map.Entry<String, String> claim : extendedClaims) {
            builder.claim(claim.getKey(), claim.getValue());
        }

        return builder.compact();
    }

    private SecretKey generateKey() {
        byte[] encodedKey = Base64.getDecoder().decode(secretSalt);
        return new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
    }

}
